<!-- WangEditor 富文本编辑器 插件地址：https://www.wangeditor.com/ -->
<template>
  <div class="editor-wrapper">
    <Toolbar
      class="editor-toolbar"
      :editor="editorRef"
      :mode="mode"
      :defaultConfig="toolbarConfig"
    />
    <Editor
      :style="{ height: height, overflowY: 'hidden' }"
      v-model="modelValue"
      :mode="mode"
      :defaultConfig="editorConfig"
      @onCreated="onCreateEditor"
    />

    <!-- 素材库选择对话框 -->
    <el-dialog v-model="materialDialogVisible" title="素材库" width="800px" destroy-on-close>
      <div class="material-dialog-header">
        <el-radio-group
          v-model="materialQueryParams.isCollection"
          @change="handleMaterialFilterChange"
        >
          <el-radio-button :label="0">全部</el-radio-button>
          <el-radio-button :label="1">收藏</el-radio-button>
        </el-radio-group>
      </div>

      <div class="material-grid">
        <el-empty v-if="materialList.length === 0" description="暂无素材" />
        <el-card
          v-for="item in materialList"
          :key="item.id"
          class="material-item"
          :body-style="{ padding: '0px' }"
          @click="handleSelectMaterial(item.url)"
        >
          <el-image :src="item.url" fit="cover" class="material-image" />
        </el-card>
      </div>

      <div class="material-dialog-footer">
        <el-pagination
          v-model:current-page="materialQueryParams.page"
          v-model:page-size="materialQueryParams.size"
          :total="materialTotal"
          :page-sizes="[12, 24, 36, 48]"
          layout="total, sizes, prev, pager, next"
          @size-change="handleMaterialSizeChange"
          @current-change="handleMaterialPageChange"
        />
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
  import '@wangeditor/editor/dist/css/style.css'
  import { onBeforeUnmount, onMounted, shallowRef, computed } from 'vue'
  import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
  import { useUserStore } from '@/store/modules/user'
  import { ElMessage } from 'element-plus'
  import EmojiText from '@/utils/ui/emojo'
  import { IDomEditor, IToolbarConfig, IEditorConfig, IButtonMenu, Boot } from '@wangeditor/editor'

  // 菜单注册状态（全局变量）
  declare global {
    interface Window {
      __WANG_EDITOR_MATERIAL_MENU_REGISTERED__?: boolean
    }
  }

  if (!window.__WANG_EDITOR_MATERIAL_MENU_REGISTERED__) {
    window.__WANG_EDITOR_MATERIAL_MENU_REGISTERED__ = false
  }

  defineOptions({ name: 'ArtWangEditor' })

  // Props 定义
  interface Props {
    /** 编辑器高度 */
    height?: string
    /** 自定义工具栏配置 */
    toolbarKeys?: string[]
    /** 插入新工具到指定位置 */
    insertKeys?: { index: number; keys: string[] }
    /** 排除的工具栏项 */
    excludeKeys?: string[]
    /** 编辑器模式 */
    mode?: 'default' | 'simple'
    /** 占位符文本 */
    placeholder?: string
    /** 上传配置 */
    uploadConfig?: {
      maxFileSize?: number
      maxNumberOfFiles?: number
      server?: string
    }
  }

  const props = withDefaults(defineProps<Props>(), {
    height: '500px',
    mode: 'default',
    placeholder: '请输入内容...',
    excludeKeys: () => ['fontFamily']
  })

  const modelValue = defineModel<string>({ required: true })

  // 编辑器实例
  const editorRef = shallowRef<IDomEditor>()
  const userStore = useUserStore()

  // 常量配置
  const DEFAULT_UPLOAD_CONFIG = {
    maxFileSize: 3 * 1024 * 1024, // 3MB
    maxNumberOfFiles: 10,
    fieldName: 'file',
    allowedFileTypes: ['image/*']
  } as const

  // 图标映射配置
  const ICON_MAP = {
    bold: '&#xe630;',
    blockquote: '&#xe61c;',
    underline: '&#xe65a;',
    italic: '&#xe638;',
    'group-more-style': '&#xe648;',
    color: '&#xe68c;',
    bgColor: '&#xe691;',
    bulletedList: '&#xe64e;',
    numberedList: '&#xe66c;',
    todo: '&#xe641;',
    'group-justify': '&#xe67e;',
    'group-indent': '&#xe63e;',
    emotion: '&#xe690;',
    insertLink: '&#xe63a;',
    'group-image': '&#xe634;',
    insertTable: '&#xe67b;',
    codeBlock: '&#xe68b;',
    divider: '&#xe66d;',
    undo: '&#xe65e;',
    redo: '&#xe659;',
    fullScreen: '&#xe633;',
    tableFullWidth: '&#xe67b;'
  } as const

  // 计算属性：上传服务器地址
  const uploadServer = computed(
    () => props.uploadConfig?.server || `${import.meta.env.VITE_API_URL}/wemedia/common/upload`
  )

  // 合并上传配置
  const mergedUploadConfig = computed(() => ({
    ...DEFAULT_UPLOAD_CONFIG,
    ...props.uploadConfig
  }))

  // 工具栏配置
  const toolbarConfig = computed((): Partial<IToolbarConfig> => {
    const config: Partial<IToolbarConfig> = {}

    // 完全自定义工具栏
    if (props.toolbarKeys && props.toolbarKeys.length > 0) {
      config.toolbarKeys = props.toolbarKeys
    } else {
      // 默认工具栏配置，确保包含素材库按钮
      config.toolbarKeys = [
        'headerSelect',
        'blockquote',
        '|',
        'bold',
        'underline',
        'italic',
        {
          key: 'group-more-style',
          title: '更多',
          iconSvg:
            '<svg viewBox="0 0 1024 1024"><path d="M204.8 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M505.6 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path><path d="M806.4 505.6m-76.8 0a76.8 76.8 0 1 0 153.6 0 76.8 76.8 0 1 0-153.6 0Z"></path></svg>',
          menuKeys: ['through', 'code', 'sup', 'sub', 'clearStyle']
        },
        '|',
        'color',
        'bgColor',
        '|',
        'fontSize',
        'fontFamily',
        'lineHeight',
        '|',
        'bulletedList',
        'numberedList',
        'todo',
        {
          key: 'group-justify',
          title: '对齐',
          iconSvg:
            '<svg viewBox="0 0 1024 1024"><path d="M768 793.6v102.4H51.2v-102.4h716.8z m204.8-230.4v102.4H51.2v-102.4h921.6z m-204.8-230.4v102.4H51.2v-102.4h716.8zM972.8 102.4v102.4H51.2V102.4h921.6z"></path></svg>',
          menuKeys: ['justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify']
        },
        {
          key: 'group-indent',
          title: '缩进',
          iconSvg:
            '<svg viewBox="0 0 1024 1024"><path d="M0 64h1024v128H0z m384 192h640v128H384z m0 192h640v128H384z m0 192h640v128H384z m0 192h640v128H384zM0 256v512l256-256z"></path></svg>',
          menuKeys: ['indent', 'delIndent']
        },
        '|',
        'emotion',
        'insertLink',
        {
          key: 'group-image',
          title: '图片',
          iconSvg:
            '<svg viewBox="0 0 1024 1024"><path d="M959.877 128l0.123 0.123v767.775l-0.123 0.122H64.102l-0.122-0.122V128.123l0.122-0.123h895.775zM960 64H64C28.795 64 0 92.795 0 128v768c0 35.205 28.795 64 64 64h896c35.205 0 64-28.795 64-64V128c0-35.205-28.795-64-64-64zM832 288.01c0 53.023-42.988 96.01-96.01 96.01s-96.01-42.987-96.01-96.01S682.967 192 735.99 192 832 234.988 832 288.01zM896 832H128V704l224.01-384 256 320h64l224.01-192z"></path></svg>',
          menuKeys: ['insertImage', 'uploadImage', menuKey]
        },
        'insertTable',
        'codeBlock',
        'divider',
        '|',
        'undo',
        'redo',
        '|',
        'fullScreen'
      ]
    }

    // 插入新工具
    if (props.insertKeys) {
      config.insertKeys = props.insertKeys
    }

    // 排除工具
    if (props.excludeKeys && props.excludeKeys.length > 0) {
      config.excludeKeys = props.excludeKeys
    }

    return config
  })

  import { ref } from 'vue'

  // 素材库选择对话框
  const materialDialogVisible = ref(false)
  const materialList = ref<any[]>([])
  const materialTotal = ref(0)
  const materialQueryParams = ref({
    page: 1,
    size: 12,
    isCollection: 0
  })

  // 当前插入函数
  let currentInsertFn: ((url: string, alt: string, href: string) => void) | null = null

  // 加载素材列表
  const loadMaterialList = async () => {
    try {
      const { WmMaterialService } = await import('@/api/wmMaterialApi')
      const res = await WmMaterialService.getMaterialList(materialQueryParams.value)
      materialList.value = res.records || []
      materialTotal.value = res.total || 0
    } catch (error) {
      console.error('加载素材库失败:', error)
      ElMessage.error('加载素材库失败')
    }
  }

  // 素材分页变化
  const handleMaterialPageChange = (page: number) => {
    materialQueryParams.value.page = page
    loadMaterialList()
  }

  // 素材每页数量变化
  const handleMaterialSizeChange = (size: number) => {
    materialQueryParams.value.size = size
    materialQueryParams.value.page = 1
    loadMaterialList()
  }

  // 素材筛选变化
  const handleMaterialFilterChange = () => {
    materialQueryParams.value.page = 1
    loadMaterialList()
  }

  // 处理素材选择
  const handleSelectMaterial = (url: string) => {
    if (currentInsertFn) {
      // 使用与默认插入图片相同的参数格式
      currentInsertFn(url, '素材图片', '')
      materialDialogVisible.value = false
      currentInsertFn = null
    }
  }

  // 创建菜单类的工厂函数
  const createInsertMaterialImageMenu = (dialogVisible: any, loadMaterials: any) => {
    return class InsertMaterialImageMenu implements IButtonMenu {
      constructor() {
        this.title = '本地素材'
        this.iconSvg =
          '<svg viewBox="0 0 1024 1024"><path d="M832 64H192C121.6 64 64 121.6 64 192v640c0 70.4 57.6 128 128 128h640c70.4 0 128-57.6 128-128V192c0-70.4-57.6-128-128-128z m64 768c0 35.2-28.8 64-64 64H192c-35.2 0-64-28.8-64-64V192c0-35.2 28.8-64 64-64h640c35.2 0 64 28.8 64 64v640z"></path><path d="M208 736h608c17.6 0 32-14.4 32-32V320c0-17.6-14.4-32-32-32H208c-17.6 0-32 14.4-32 32v384c0 17.6 14.4 32 32 32z m32-384h544v320H240V352z"></path><path d="M344 480m-56 0a56 56 0 1 0 112 0 56 56 0 1 0-112 0Z"></path></svg>'
        this.tag = 'button'
      }

      // 菜单标题
      title: string
      // 菜单图标
      iconSvg: string
      // 菜单类型
      tag: string

      // 获取菜单值
      getValue(): string | boolean {
        return ''
      }

      // 是否激活
      isActive(): boolean {
        return false
      }

      // 是否禁用
      isDisabled(): boolean {
        return false
      }

      // 执行命令
      exec(editor: IDomEditor): void {
        // 保存编辑器实例，用于后续插入图片
        currentInsertFn = (url: string, alt: string) => {
          // 使用DOM API直接插入图片
          const img = document.createElement('img')
          img.src = url
          img.alt = alt
          img.style.width = '100%'
          img.style.maxWidth = '100%'

          // 将图片插入到编辑器
          editor.dangerouslyInsertHtml(img.outerHTML)
        }

        // 打开素材库对话框
        dialogVisible.value = true
        loadMaterials()
      }
    }
  }

  // 生成唯一的菜单key
  const menuKey = `insertMaterialImage_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`

  // 注册素材库菜单
  const registerMaterialMenu = () => {
    try {
      const InsertMaterialImageMenu = createInsertMaterialImageMenu(
        materialDialogVisible,
        loadMaterialList
      )
      Boot.registerMenu({
        key: menuKey,
        factory() {
          return new InsertMaterialImageMenu()
        }
      })
    } catch (error) {
      // 如果菜单已存在，忽略错误
      console.warn('菜单注册失败，可能已存在:', error)
    }
  }

  // 编辑器配置
  const editorConfig: Partial<IEditorConfig> = {
    placeholder: props.placeholder,
    MENU_CONF: {
      uploadImage: {
        fieldName: mergedUploadConfig.value.fieldName,
        maxFileSize: mergedUploadConfig.value.maxFileSize,
        maxNumberOfFiles: mergedUploadConfig.value.maxNumberOfFiles,
        allowedFileTypes: mergedUploadConfig.value.allowedFileTypes,
        server: uploadServer.value,
        headers: {
          Authorization: userStore.accessToken
        },
        // 自定义上传图片的回调函数
        customInsert(res: any, insertFn: (url: string) => void) {
          if (res.errno === 0 && res.data && res.data.length > 0) {
            const url = res.data[0].replace(/["']/g, '').trim()
            insertFn(url) // ✅ 类型安全：知道 insertFn 接受一个 string
            ElMessage.success(`图片上传成功 ${EmojiText[200]}`)
          } else {
            ElMessage.error(`图片上传失败 ${EmojiText[500]}`)
          }
        },
        onSuccess() {
          // 使用customInsert处理，这里不需要额外操作
        },
        onError(file: File, err: any, res: any) {
          console.error('图片上传失败:', err, res)
          ElMessage.error(`图片上传失败 ${EmojiText[500]}`)
        }
      }
    }
  }

  // 编辑器创建回调
  const onCreateEditor = (editor: IDomEditor) => {
    editorRef.value = editor

    // 在编辑器创建完成后注册菜单
    registerMaterialMenu()

    // 监听全屏事件
    editor.on('fullScreen', () => {
      console.log('编辑器进入全屏模式')
    })
  }

  // 优化的图标替换函数
  const overrideIcons = () => {
    requestAnimationFrame(() => {
      Object.entries(ICON_MAP).forEach(([menuKey, iconCode]) => {
        const button = document.querySelector(`button[data-menu-key="${menuKey}"]`)
        if (button) {
          button.innerHTML = `<i class='iconfont-sys'>${iconCode}</i>`
        }
      })
    })
  }

  // 暴露编辑器实例和方法
  defineExpose({
    /** 获取编辑器实例 */
    getEditor: () => editorRef.value,
    /** 设置编辑器内容 */
    setHtml: (html: string) => editorRef.value?.setHtml(html),
    /** 获取编辑器内容 */
    getHtml: () => editorRef.value?.getHtml(),
    /** 清空编辑器 */
    clear: () => editorRef.value?.clear(),
    /** 聚焦编辑器 */
    focus: () => editorRef.value?.focus()
  })

  // 生命周期
  onMounted(() => {
    overrideIcons()
  })

  onBeforeUnmount(() => {
    const editor = editorRef.value
    if (editor) {
      editor.destroy()
    }
  })
</script>

<style lang="scss">
  @use './style';
</style>
